<template>
  <span>Heatmap</span>
  <!-- 添加按钮 -->
  <button @click="handleButtonClick">更新图表</button>
  <div ref="chartContainer" style="width: 100%; height: 40vh;"></div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import * as echarts from 'echarts';
import { useStore } from 'vuex';
import * as tf from '@tensorflow/tfjs';

const store = useStore(); // 获取Vuex store

// 数据定义
const hours = Array.from({ length: 80 }, (_, i) => (i + 1).toString());
const days = [
  'Fst1-K', 'Fst2-K', 'Sec1-K', 'Sec2-K', 'Fst-K*', 'Sec-K*'
];
const heatmapData = ref([]); // 热力图数据

// 将 backendData 改为 ref
const backendData = ref({
  categories: [{ name: 'Root' }, { name: 'FirstDegree' }, { name: 'SecondDegree' }],
  nodes: [
    { id: 'M25811357', name: 'M25811357', category: 'Root', vector: [1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0] },
    { id: 'D1317475', name: 'D1317475', category: 'Root', vector: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] },
    { id: 'D1317346', name: 'D1317346', category: 'FirstDegree', vector: [1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] },
    { id: 'D1275554', name: 'D1275554', category: 'SecondDegree', vector: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0] },
    { id: 'M20395646', name: 'M20395646', category: 'FirstDegree', vector: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] },
    { id: 'M1294963', name: 'M1294963', category: 'FirstDegree', vector: [1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] },
    { id: 'M1294007', name: 'M1294007', category: 'FirstDegree', vector: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0] },
    { id: 'M1297743', name: 'M1297743', category: 'FirstDegree', vector: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] },
    { id: 'D1054398', name: 'D1054398', category: 'SecondDegree', vector: [0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0] }
  ],
  links: [
    ['D1317346', 'M25811357'], ['D1275554', 'M20395646'], ['M20395646', 'D1317475'],
    ['M1294963', 'D1054398'], ['M1294963', 'D1317475'], ['D1317475', 'M1294007'],
    ['D1317475', 'M1297743'], ['M1294007', 'D1054398'], ['M1297743', 'D1054398'],
    ['M25811357', 'D1317475'], ['M25811357', 'D1317346'], ['D1317475', 'M20395646'],
    ['D1317475', 'M1294963']
  ]
});

const chartContainer = ref(null);

// 处理按钮点击事件
const handleButtonClick = async () => {
  const dataResult = store.state.dataResult; // 获取Vuex中的dataResult

  if (dataResult === null) {
    alert('空数据集'); // 弹出弹窗提示空数据集
  } else {
    // 检查 dataResult 是否包含有效的 nodes 和 links 数组
    if (!dataResult.nodes || dataResult.nodes.length < 2 || !dataResult.links || !Array.isArray(dataResult.links)) {
      console.error("dataResult.nodes 或 dataResult.links 数据不完整，无法更新图表");
      alert('数据格式不正确，无法更新图表');
      return;
    }

    // 更新 backendData
    backendData.value = dataResult;
    console.log("backendData 已更新:", backendData.value);

    // 确保 backendData.value.nodes 和 backendData.value.links 存在且有足够的元素
    if (!backendData.value.nodes || backendData.value.nodes.length < 2 || !backendData.value.links || !Array.isArray(backendData.value.links)) {
      console.error("backendData.nodes 或 backendData.links 数据不完整，无法更新图表");
      return;
    }

    // 手动重新计算依赖的数据
    const FirstRootId = backendData.value.nodes[0].id;
    const SecondRootId = backendData.value.nodes[1].id;

    // 调用函数时传递 backendData.value
    const firstRootNodeVectorsAndIds = getRandomFirstDegreeNeighborsVectors(backendData.value, FirstRootId);
    const firstRootNodeVectors = firstRootNodeVectorsAndIds.concatenatedVectors;
    const firstRootNeighborsNodes = firstRootNodeVectorsAndIds.selectedNodeIds;

    const secondRootNodeVectorsAndIds = getRandomFirstDegreeNeighborsVectors(backendData.value, SecondRootId);
    const secondRootNodeVectors = secondRootNodeVectorsAndIds.concatenatedVectors;
    const secondRootNeighborsNodes = secondRootNodeVectorsAndIds.selectedNodeIds;

    // 获取第一个根节点的二阶邻居节点向量信息
    const secondDegreeDataForFirstRoot = getRandomSecondDegreeNeighborsVectors(backendData.value, firstRootNeighborsNodes);
    const firstRootNodeSecondDegreeVectors = secondDegreeDataForFirstRoot.concatenatedVectors;
    const firstRootNodeSecondDegreeNodes = secondDegreeDataForFirstRoot.allSecondDegreeIds;

    // 获取第二个根节点的二阶邻居节点向量信息
    const secondDegreeDataForSecondRoot = getRandomSecondDegreeNeighborsVectors(backendData.value, secondRootNeighborsNodes);
    const secondRootNodeSecondDegreeVectors = secondDegreeDataForSecondRoot.concatenatedVectors;
    const secondRootNodeSecondDegreeNodes = secondDegreeDataForSecondRoot.allSecondDegreeIds;

    // 将一阶和二阶邻居特征重塑为合适的形状
    const NUM_FEA = 16;
    const NUM_NEIGHBOR = 5;
    const EMB_DIM = 16;
    const FstNeigh1 = tf.tensor1d(firstRootNodeVectors).reshape([1, NUM_NEIGHBOR, NUM_FEA]);
    const FstNeigh2 = tf.tensor1d(firstRootNodeSecondDegreeVectors).reshape([1, NUM_NEIGHBOR, NUM_FEA]);
    const SecNeigh1 = tf.tensor1d(secondRootNodeVectors).reshape([1, NUM_NEIGHBOR, NUM_FEA]);
    const SecNeigh2 = tf.tensor1d(secondRootNodeSecondDegreeVectors).reshape([1, NUM_NEIGHBOR, NUM_FEA]);

    // 连接一阶和二阶邻居特征
    const combinedNeigh1 = tf.concat([FstNeigh1, FstNeigh2], 2);
    const combinedNeigh2 = tf.concat([SecNeigh1, SecNeigh2], 2);

    // 通过全连接层处理连接后的特征
    const denseLayer = tf.layers.dense({
      units: EMB_DIM,
      activation: 'elu',
      use_bias: true,
      kernel_initializer: 'glorotNormal',
      kernel_regularizer: 'l2'
    });

    // 将连接后的特征传递给全连接层
    const emb1 = denseLayer.apply(combinedNeigh1);
    const emb2 = denseLayer.apply(combinedNeigh2);

    // 使用异步的 data 方法获取数据
    const finalEmbArray1 = await emb1.as1D().data();
    const finalEmbArray2 = await emb2.as1D().data();
    console.log('最终的 Fst 根节点嵌入表示:', finalEmbArray1);
    console.log('最终的 Sec 根节点嵌入表示:', finalEmbArray2);

    // 更新图表
    if (!chartContainer.value) {
      console.error("chartContainer 未正确引用");
      return;
    }
    const myChart = echarts.getInstanceByDom(chartContainer.value) || echarts.init(chartContainer.value);
    if (!myChart) {
      console.error("无法初始化或获取 Echarts 实例");
      return;
    }

    // 调用 updateChart 并传递所有必要的数据
    updateChart(
      myChart,
      firstRootNodeVectors,
      firstRootNodeSecondDegreeVectors,
      secondRootNodeVectors,
      secondRootNodeSecondDegreeVectors,
      finalEmbArray1, 
      finalEmbArray2  
    );
  }
};

// 定义函数来获取根节点的所有一阶邻居节点的向量，并去除重复项
function getRandomFirstDegreeNeighborsVectors(backendData, rootId) {
  const nodes = backendData.nodes; // 直接访问 nodes，因为 backendData 已经是 .value
  const links = backendData.links; // 直接访问 links，因为 backendData 已经是 .value

  // 确保 links 是一个数组
  if (!Array.isArray(links)) {
    console.error("links 不是一个数组:", links);
    return {
      concatenatedVectors: [],
      selectedNodeIds: []
    };
  }

  // 查找根节点的所有一阶邻居节点
  const firstDegreeNeighbors = links
    .filter(link => link.includes(rootId)) // 找到所有包含根节点ID的链接
    .map(link => {
      const neighborNode = nodes.find(node => (node.id === link[0] && node.id !== rootId) || (node.id === link[1] && node.id !== rootId));
      return neighborNode ? { id: neighborNode.id, vector: neighborNode.vector } : null; // 获取邻居节点的id和向量
    })
    .filter(vector => vector !== null); // 过滤掉未找到的节点向量

  // 随机选择5个一阶邻居节点的向量，允许重复
  const randomVectors = [];
  const selectedNodeIds = [];
  for (let i = 0; i < 5 && firstDegreeNeighbors.length > 0; i++) {
    const randomIndex = Math.floor(Math.random() * firstDegreeNeighbors.length);
    const selectedNeighbor = firstDegreeNeighbors[randomIndex];
    randomVectors.push(selectedNeighbor.vector);
    selectedNodeIds.push(selectedNeighbor.id);
  }
  // 拼接所有选中的一阶邻居节点的向量
  const concatenatedVectors = randomVectors.reduce((acc, vector) => acc.concat(vector), []);

  return {
    concatenatedVectors,
    selectedNodeIds
  };
}

// 定义函数来获取节点的所有二阶邻居节点的向量
function getRandomSecondDegreeNeighborsVectors(backendData, selectedNodeIds) {
  const nodes = backendData.nodes; // 直接访问 nodes，因为 backendData 已经是 .value
  const links = backendData.links; // 直接访问 links，因为 backendData 已经是 .value

  let concatenatedVectors = []; // 用于存储所有二阶邻居节点的向量
  let allSecondDegreeIds = []; // 用于存储所有二阶邻居节点的ID
  selectedNodeIds.forEach(firstDegreeId => {
    // 查找每个一阶邻居的所有二阶邻居节点
    const secondDegreeNeighbors = links
      .filter(link => link.includes(firstDegreeId))
      .map(link => {
        const secondDegreeNodeId = link[0] === firstDegreeId ? link[1] : link[0];
        const secondDegreeNode = nodes.find(node => node.id === secondDegreeNodeId);
        return secondDegreeNode ? { id: secondDegreeNodeId, vector: secondDegreeNode.vector } : null;
      })
      .filter(node => node !== null); // 过滤掉未找到的节点

    // 随机选择5个二阶邻居节点的向量，允许重复
    for (let i = 0; i < 5 && secondDegreeNeighbors.length > 0; i++) {
      const randomIndex = Math.floor(Math.random() * secondDegreeNeighbors.length);
      const selectedNeighbor = secondDegreeNeighbors[randomIndex];
      // 将向量值展开并添加到concatenatedVectors数组中
      concatenatedVectors = concatenatedVectors.concat(selectedNeighbor.vector);
      allSecondDegreeIds.push(selectedNeighbor.id); // 添加ID
    }
  });
  function aggregateVectors(concatenatedVectors) {
    // 确保concatenatedVectors长度为400
    if (concatenatedVectors.length !== 400) {
      throw new Error('Input array must be of length 400.');
    }

    const groupSize = 16; // 每组的大小
    const numGroups = 25; // 总共的组数
    const stepSize = 5; // 每次跳过的组数

    let aggregatedVectors = []; // 存储最终结果的数组

    // 遍历每5组，计算平均值
    for (let i = 0; i < numGroups; i += stepSize) {
      // 对于每组，计算5个对应位置的平均值
      for (let j = 0; j < groupSize; j++) {
        let sum = 0;
        // 计算5组对应位置的值的总和
        for (let k = 0; k < stepSize; k++) {
          const idx = i + k;
          sum += concatenatedVectors[idx * groupSize + j];
        }
        // 计算平均值，并添加到结果数组中
        const average = sum / 5;
        aggregatedVectors.push(average);
      }
    }

    return aggregatedVectors;
  }
  concatenatedVectors = aggregateVectors(concatenatedVectors);
  return {
    concatenatedVectors,
    allSecondDegreeIds
  };
}

// 初始化图表
onMounted(async () => {
  if (!chartContainer.value) {
    console.error("chartContainer 未正确引用");
    return;
  }
  const myChart = echarts.getInstanceByDom(chartContainer.value) || echarts.init(chartContainer.value);
  if (!myChart) {
    console.error("无法初始化或获取 Echarts 实例");
    return;
  }
});

const updateChart = (
  myChart,
      firstRootNodeVectors,
      firstRootNodeSecondDegreeVectors,
      secondRootNodeVectors,
      secondRootNodeSecondDegreeVectors,
      finalEmbArray1, 
      finalEmbArray2  
) => {
  const option = {
    tooltip: {
      position: 'top'
    },
    grid: {
      height: '50%',
      top: '10%',
      left: '15%'
    },
    series: []
  };

  option.visualMap = {
    min: 0,
    max: 1,
    calculable: true,
    orient: 'horizontal',
    left: 'center',
    bottom: '15%',
    show: false,
    color: ['#FF0C00', '#FDB6B6', '#FFFBFB']
  };
  option.xAxis = {
    type: 'category',
    data: hours,
    splitArea: {
      show: true
    }
  };
  option.yAxis = {
    type: 'category',
    data: days,
    splitArea: {
      show: true
    }
  };

  // 在这里根据新传递的参数更新 heatmapData 或直接使用它们
  const heatmapData = [];
  for (let i = 0; i < firstRootNodeVectors.length; i++) {
    heatmapData.push([i, 0, firstRootNodeVectors[i]]); // Fst1-K
  }
  for (let i = 0; i < firstRootNodeSecondDegreeVectors.length; i++) {
    heatmapData.push([i, 1, firstRootNodeSecondDegreeVectors[i]]); // Fst2-K
  }
  for (let i = 0; i < secondRootNodeVectors.length; i++) {
    heatmapData.push([i, 2, secondRootNodeVectors[i]]); // Sec1-K
  }
  for (let i = 0; i < secondRootNodeSecondDegreeVectors.length; i++) {
    heatmapData.push([i, 3, secondRootNodeSecondDegreeVectors[i]]); // Sec2-K
  }
  for (let i = 0; i < finalEmbArray1.length; i++) {
    heatmapData.push([i, 4, finalEmbArray1[i]]); // Fst-K*
  }
  for (let i = 0; i < finalEmbArray2.length; i++) {
    heatmapData.push([i, 5, finalEmbArray2[i]]); // Sec-K*
  }

  option.series.push({
    name: 'Punch Card',
    type: 'heatmap',
    data: heatmapData,
    label: {
      show: false
    },
    emphasis: {
      itemStyle: {
        shadowBlur: 10,
        shadowColor: 'rgba(0, 0, 0, 0.5)'
      }
    }
  });

  myChart.clear(); // 清除之前的配置
  myChart.setOption(option);
};
</script>

<style scoped>

input:checked + .slider {
  background-color: #2196f3;
}

input:checked + .slider:before {
  transform: translateX(26px);
}

.round {
  border-radius: 34px;
}
</style>